package org.wak.character.display
{
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.geom.Point;
	
	import org.wak.main.AdventureMaster;
	import org.wak.utils.BitmapMovieClip;
	import org.wak.utils.Utils;

	/**
	 * A very rustic and simple tiled Bitmap based CharacterDisplay. 
	 * Don't support animations on turns nor animations in standing positions.
	 * 
	 */	
	public class SingleBmpCharacterDisplay extends AbstractCharacterDisplay
	{
		private var mWalkRight:BitmapMovieClip ;
		private var mWalkLeft:BitmapMovieClip ;
		private var mWalkFront:BitmapMovieClip ;
		private var mWalkBack:BitmapMovieClip ;
		
		private var mStandingLeft:BitmapMovieClip ;
		private var mStandingRight:BitmapMovieClip ;
		private var mStandingFront:BitmapMovieClip ;
		private var mStandingBack:BitmapMovieClip ;
		
		private var mCurrentAnim:BitmapMovieClip ;
		
		private var mCurrentBehaviour:String = "";
		
		// local reference of the resource manaer
		private var mResourceMngr:Class ;
		
		// Asoc Array of anim behaviour id -> BitmapMovieClip.
		private var mBehaviours:Array = null ;
		
		private var mPrevCoordinates:Point = null ;
		
		
		
		
		/**
		 * Constructor 
		 * @param pDef ICharacterDisplayDefinition with the data to create the character display.
		 * 
		 */		
		public function SingleBmpCharacterDisplay(pDef:ICharacterDisplayDefinition)
		{
			super();
			mResourceMngr = AdventureMaster.Resources ;
			
			mDisplayId = pDef.GetCharDisplayId() ;
			
			mBehaviours = new Array();
			
			
			var fNewBmpclip:BitmapMovieClip = null ;
			
			for each( var anim:Animation in pDef.GetAnimBehaviours() )
			{
				fNewBmpclip = new BitmapMovieClip( new mResourceMngr[anim.resourceId] , anim.rows, anim.cols );
				
				AddBuiltinAnim(fNewBmpclip, anim.behaviour );
				fNewBmpclip.frameDelay = pDef.GetFrameDelay() ;
				
				if( anim.offsetX != 0 )
				{
					fNewBmpclip.x = anim.offsetX ;
				}
				else
				{
					fNewBmpclip.x = -(fNewBmpclip.width/2) ;
				}
				
				if( anim.offsetY != 0 )
				{
					fNewBmpclip.y = anim.offsetY ;
				}
				else
				{
					fNewBmpclip.y = -1*(fNewBmpclip.height) ;
				}
				
				
				mBehaviours[anim.behaviour] = fNewBmpclip ;
				if(anim.flipH )
					fNewBmpclip.scaleX = -1;
					
				if(anim.flipV )
					fNewBmpclip.scaleY = -1;
				
			}
			 
			mCurrentAnim = mStandingLeft ;
			mCurrentBehaviour = AnimationBehaviour.STANDING_LEFT ;
			
			mPrevCoordinates = new Point( this.x, this.y);
			
			mMoveSpeed = pDef.GetMoveSpeed() ;
			
			if(pDef.GetPortrait() != "")
			{
				var fTempPortrait:DisplayObject = new mResourceMngr[pDef.GetPortrait()];
				if(fTempPortrait is MovieClip )
				{
					mPortrait = fTempPortrait as MovieClip;
				}
				else 
				{
					mPortrait = new MovieClip();
					mPortrait.addChild(fTempPortrait);
				}
			}
			
			mUpdatePerspective = pDef.perspectiveEnabled ;
			
			this.scaleX = pDef.scale ;
			this.scaleY = pDef.scale ;
				
		}
		
		public override function get stageX():Number
		{
			return (this.parent.x + this.x) ;
		}
		
		public override function get stageY():Number
		{
			return (this.parent.y + this.y) ;
		}
		
		public override function get dialogX():Number
		{
			return this.stageX ;
		}
		
		public override function get dialogY():Number
		{
			return (this.stageY - (mCurrentAnim.height * mCurrentAnim.scaleY * this.scaleY) ) ;
			//return this.stageY ;
			//return (this.stageY - (mCurrentAnim.height * mCurrentAnim.scaleY * this.scaleY) - 10) ;
		}
		
		public override function get currentBehaviour():String
		{
			return mCurrentBehaviour ;
		}
		
		
		private function AddBuiltinAnim(pClip:BitmapMovieClip, pId:String):void
		{
			switch(pId)
			{
				case AnimationBehaviour.WALK_FRONT :
				mWalkFront = pClip ;
				break;
				case AnimationBehaviour.WALK_BACK :
				mWalkBack = pClip ;
				break;
				case AnimationBehaviour.WALK_LEFT :
				mWalkLeft = pClip ;
				break;
				case AnimationBehaviour.WALK_RIGHT :
				mWalkRight = pClip ;
				break;
				case AnimationBehaviour.STANDING_FRONT :
				mStandingFront = pClip ;
				break;
				case AnimationBehaviour.STANDING_BACK :
				mStandingBack = pClip ;
				break;
				case AnimationBehaviour.STANDING_LEFT :
				mStandingLeft = pClip ;
				break;
				case AnimationBehaviour.STANDING_RIGHT :
				mStandingRight = pClip ;
				break;
				
			}
		}
		
		private var mAnimationSet:Boolean = false ;
		private var mOnPlayedFunc:Function = null ;
		private var mPlaysNumber:int = 1 ;
		private var mCurrentPlays:int = 0 ;
		
		
		public override function SetAnimBehaviour(pAnimBehaviour:String, pPlays:int = 1, pOnPlayed:Function = null):void
		{
			
			if( pAnimBehaviour == "")
				return ;
			
			
			var fNewAnim:BitmapMovieClip = mBehaviours[pAnimBehaviour] as BitmapMovieClip ;
			
			if(fNewAnim == null ) 
			{
				throw new Error(mDisplayId +" CharacterDisplay Animation Behaviour for " +pAnimBehaviour+" unknown.");
				return ;
			}
				
			mAnimationSet = true ;
							
			if(this.contains(mCurrentAnim))
			{
				this.removeChild(mCurrentAnim);
				mCurrentAnim.stop();
			}
			
			mCurrentAnim = fNewAnim ;
			mCurrentBehaviour = pAnimBehaviour ;
			
			mPlaysNumber = pPlays ;
			mOnPlayedFunc = pOnPlayed ;
			mCurrentPlays = 0 ;
			if(mPlaysNumber > 0)
				mCurrentAnim.addEventListener( BitmapMovieClip.ANIM_COMPLETE_EVENT,OnAnimPlaysCompleted,false,0,true);
			
			this.addChild( mCurrentAnim );
				mCurrentAnim.play();	
			
			mPrevCoordinates.x = this.x ;
			mPrevCoordinates.y = this.y ;
			
			
		}
		
		protected function OnAnimPlaysCompleted(event:Event):void
		{
			if(mCurrentPlays == mPlaysNumber)
			{
				mCurrentAnim.stop();
				mCurrentAnim.removeEventListener( BitmapMovieClip.ANIM_COMPLETE_EVENT,OnAnimPlaysCompleted);
				if(mOnPlayedFunc != null)
				{
					mOnPlayedFunc();
					mOnPlayedFunc = null ;
				}
			}
			
			mCurrentPlays++ ;
		}
		
		
		protected override function OnAddedToStage(event:Event):void
		{
			super.OnAddedToStage(event);
			mPrevCoordinates.x = this.x ;
			mPrevCoordinates.y = this.y ;
			
			
		}
		
		protected override function OnRemovedFromStage(event:Event):void
		{
			super.OnRemovedFromStage(event);
			 
			/*
			if( this.contains( this.mCurrentAnim ) )
			{
				this.removeChild( this.mCurrentAnim );
				this.mCurrentAnim.stop() ;
			}
			
			if( this.contains( this.mCurrentStanding ) )
				this.removeChild( this.mCurrentStanding );
			
			mCurrentStanding = mStandingLeft ;
			this.addChild( mCurrentStanding );
			*/
			
			
			this.addEventListener( Event.ADDED_TO_STAGE, OnAddedToStage );
		}
		
		public override function toString():String
		{
			return mDisplayId + " bl:"+ this.y ;
		}
		
		private var mCallUpdateAnimOnce:Boolean = true ;
		
		public override function Update(event:Event):void
		{
			super.Update(event);
			
			// if this is moving.
			if( (mPrevCoordinates.x != this.x) || (mPrevCoordinates.y != this.y) )
			{
				//trace("1:"+mMovingTilesAngle)
				UpdateCharAnimation(this.mIsMoving, this.mMovingTilesAngle );
				mCallUpdateAnimOnce = true ;
			}
			else// else is still.
			{
				// we only call the UpdateCharAnimation Once	
				if(mCallUpdateAnimOnce)
				{
					//trace("2:"+mMovingTilesAngle)
					mCallUpdateAnimOnce = false ;
					UpdateCharAnimation(this.mIsMoving, this.mMovingTilesAngle );
				}
			}
			
			
			mPrevCoordinates.x = this.x ;
			mPrevCoordinates.y = this.y ;
			//trace("player update:"+this.x + " - " + this.y)
			
		}
		
		
		
		private function UpdateCharAnimation(pIsMoving:Boolean, pAngle:Number):void
		{
			//trace("-:"+pAngle);			
			pAngle = Math.round(Utils.ToDeg(pAngle)) ;
			//trace("UpdateCharAnimation: pAngle: "+ pAngle + " moving:"+pIsMoving);
			
			var fNewAnim:BitmapMovieClip ; 
			var fNewAnimBehaviour:String = "" ;
			
			if(mAnimationSet)
			{
				//trace("mAnimationSet");
				mAnimationSet = false ;
				return ;
			}
			
			if(pIsMoving)
			{
				//trace("UpdateCharAnimation:"+ pAngle );		
				switch( pAngle )
				{
					case 90:
						fNewAnim = mWalkFront ;
						fNewAnimBehaviour = AnimationBehaviour.WALK_FRONT ;
						break;
					case 270:
						fNewAnim = mWalkBack ;
						fNewAnimBehaviour = AnimationBehaviour.WALK_BACK ;
						break ;
					case 180:
					case 135:
					case 225:
						fNewAnim = mWalkLeft ;
						fNewAnimBehaviour = AnimationBehaviour.WALK_LEFT ;
						break;
					case 0:
					case 45:
					case 315:
						fNewAnim = mWalkRight ;
						fNewAnimBehaviour = AnimationBehaviour.WALK_RIGHT ;
						break;
						
						
				}
						
				if(fNewAnim != this.mCurrentAnim) 
				{
					if( this.contains( this.mCurrentAnim ) )
					{
						this.removeChild( this.mCurrentAnim );
						this.mCurrentAnim.stop() ;
					}
					
					if( fNewAnim != null)
					{
						this.addChild( fNewAnim );
						fNewAnim.play();
						this.mCurrentAnim = fNewAnim ;
						mCurrentBehaviour = fNewAnimBehaviour ;
					}
					else
					{
						//trace("fNewWalk null pIsMoving:"+ pIsMoving + "  pAngle:"+ pAngle);
					}
				}
				else
				{
					if(!this.contains(fNewAnim))
					{
						this.addChild(fNewAnim);
						fNewAnim.play()
					}
				}
			}
			else // is not moving
			{
				
				switch( pAngle )
				{
					case 270:
						fNewAnim = mStandingBack ;
						fNewAnimBehaviour = AnimationBehaviour.STANDING_BACK ;
						break ;
					case 90:
						fNewAnim = mStandingFront ;
						fNewAnimBehaviour = AnimationBehaviour.STANDING_FRONT ;
						break;
					case 180:
					case 135:
					case 225:
						fNewAnim = mStandingLeft ;
						fNewAnimBehaviour = AnimationBehaviour.STANDING_LEFT ;
						break;
					case 0:
					case 45:
					case 315:
						fNewAnim = mStandingRight ;
						fNewAnimBehaviour = AnimationBehaviour.STANDING_RIGHT ;
						break;
						
				}
				
				if(fNewAnim != this.mCurrentAnim)
				{
					
					
					if( this.contains( this.mCurrentAnim ) )
					{
						this.mCurrentAnim.stop();
						this.removeChild( this.mCurrentAnim );
					}
					
					if(fNewAnim != null)
					{
						this.addChild( fNewAnim );
						this.mCurrentAnim = fNewAnim ;
						mCurrentBehaviour = fNewAnimBehaviour ;
						fNewAnim.play();
					}	
				}
				else
				{
					
					if(!this.contains(fNewAnim))
					{
						this.addChild(fNewAnim);
						fNewAnim.play();
					}
					 
				}
				
				//trace(fNewAnim == mStandingBack);
				
			}	
			
			
		}
		
	}
}